#include<cstdio>
#include<iostream>
using namespace std;
#include<unistd.h>
#include<cassert>
#include<sys/types.h>
#include<sys/wait.h>
#include<cstring>


//这里要求子进程用来写数据，父进程用来读数据
int main(){
    //1:创建管道文件
    int fds[2];
    int n = pipe(fds);//这里的pipe是一个输出型参数 3 4
    assert(n == 0);

    //2:创建子进程
    pid_t id = fork();
    if(id == 0){
        close(fds[0]);//由于子进程是用来写数据的，所以我们把他的读端给关闭了
        //开始通信写
        const char* arr = "I am childprocess,I am writing ..";
        int cnt = 0;
        while(true){
            cnt++;
            char buffer[1024];
            snprintf(buffer,sizeof buffer,"child->parent saying %s[%d],pid[%d]\n",arr,cnt,getpid());
            write(fds[1],buffer,strlen(buffer));//写是往文件的缓存区写，\0和文件无关
            sleep(1);

            //close(fds[1]);//主动关闭写进程
            //cout<<"子进程自己关闭写的管道"<<endl;
           // sleep(10000);
           // exit(0);
            //sleep(10);       
           // cout<<"count:"<<cnt<<endl;    
        }

        exit(0);
    }


    //sleep(5);
    close(fds[1]);
    //开始通信读

    // //测试情况1：子进程每10秒写入一次，但是父进程一直读，这个时候父亲进程很快就会把缓存区的数据读完
    // //这样父进程就会进入读端阻塞
    // while(true){
    //     //读到buffer
    //     char buffer[1024];
    //     cout<<"AAAAAAAAAAAAAAAAAAAAAAAAAAAAA"<<endl;
    //     //
    //     ssize_t s = read(fds[0],buffer,sizeof(buffer)-1);//要预留一个位置\0
    //     if(s > 0) buffer[s] = 0;
    //     cout<<"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"<<endl;
    //     cout<<"# "<<buffer<<"pid: "<<getpid()<<endl;
    //     //注意细节：这里的父进程没有进行sleep
    // }
    // pid_t ret = waitpid(id,NULL,0);
    // assert(ret > 0);


    //测试情况2：子进程一直进行写入数据，不sleep，但是父进程不进行读取数据会怎么样？
    //这样子进程写的文件缓存区很快就会被写满，那么就会发生写端阻塞，等待读进程读取数据后再进行写入
    // while(true){
    //     //读到buffer
    //     sleep(1000);
    //     char buffer[1024];
    //     cout<<"AAAAAAAAAAAAAAAAAAAAAAAAAAAAA"<<endl;
    //     //
    //     ssize_t s = read(fds[0],buffer,sizeof(buffer)-1);//要预留一个位置\0
    //     if(s > 0) buffer[s] = 0;
    //     cout<<"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"<<endl;
    //     cout<<"# "<<buffer<<"pid: "<<getpid()<<endl;
    //     //注意细节：这里的父进程没有进行sleep
    // }
    // pid_t ret = waitpid(id,NULL,0);
    // assert(ret > 0);


    //测试情况3：先让子进程进行写入数据，然后直接把子进程的写文件表给关闭，会发生什么
    //这个时候读端很快就会读完缓冲区的数据，这个时候就没有数据可以读取了，
    //我们可以做一个判断，如果读到0，就结束循环
    // while(true){
    //     //读到buffer
    //     //sleep(1000);
    //     char buffer[1024];
    //    // cout<<"AAAAAAAAAAAAAAAAAAAAAAAAAAAAA"<<endl;
    //     ssize_t s = read(fds[0],buffer,sizeof(buffer)-1);//要预留一个位置\0
    //     if(s > 0){
    //         buffer[s] = 0;
    //         cout<<"# "<<buffer<<"pid: "<<getpid()<<endl;

    //     }else if(s == 0){
    //         //读到结尾了
    //         cout<<"read end"<<endl;
    //         break;
    //     }
    //     //注意细节：这里的父进程没有进行sleep
    // }
    // int status = 0;
    // pid_t ret = waitpid(id,&status,0);//输出型参数
    // assert(ret > 0);



    //测试情况4:让子进程一直写入数据到缓冲区，然后把父进程的读端给关闭会发生什么？
    //这样当缓冲区被写满了以后，os会把写端给终止，也就是杀死写端进程，它是通过发送信号的方式来说明的
    // while(true){
    //     //读到buffer
    //     //sleep(1000);
    //     char buffer[1024];
    //     ssize_t s = read(fds[0],buffer,sizeof(buffer)-1);//要预留一个位置\0
    //     if(s > 0) buffer[s] = 0;
    //     cout<<"# "<<buffer<<"pid: "<<getpid()<<endl;
    //     //注意细节：这里的父进程没有进行sleep
    // }


    close(fds[0]);//关闭读端
    cout<<"父进程关闭了读取端"<<endl;
    int status = 0;
    pid_t ret = waitpid(id,&status,0);
    assert(ret == id);

    cout<<"pid->"<<ret<<":"<<(status & 0x7F) <<endl;

    // cout<<"fds[0]:"<<fds[0]<<endl;
    // cout<<"fds[1]:"<<fds[1]<<endl;
    

    return 0;
}
